/////////////////////////////////////////////////////////////////////////////
// Filename: ObjectViewer.cpp
// Description: main program
/////////////////////////////////////////////////////////////////////////////

#include "Object.h"
#include "Light.h"
#include "Transformations.h"
#include <GL/glut.h>
#include <iostream>
#include <vector>
using namespace std;

void display ();
void reshape (int width, int height);
void keyboard(unsigned char key, int x, int y);
void init ();

Object object;
Matrix4 view_matrix;
vector<Light> light_list;

bool animation=false;
float rotation_speed = 1.0f; //in degrees
float translation_speed = 0.5f;

//shading types are defined in "Object.h"
//int shading_type=WIREFRAME_SHADING; 
int shading_type=SMOOTH_SHADING;
//int shading_type=FLAT_SHADING;
//int shading_type=WIREFRAME_SHADING;

void main (int argc, char **argv){

	if(argc<2){
		cout<<"Usage: Lab2 filename.obj"<<endl;
		exit(1);
	}

	object.Load_obj(argv[1]);

	glutInit (&argc, argv);
	glutInitWindowSize (500, 500);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB|GLUT_DEPTH);
	glutCreateWindow ("Object viewer");
	glutDisplayFunc (display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);

	init ();
	glutMainLoop ();
}

void display (void){
	glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	if(animation){
		object.model_matrix*=rotate(Vector3(0,0,1), rotation_speed,Vector3(0,0,0));
	}

	object.Display(view_matrix, light_list, shading_type);	

	glutSwapBuffers ();
	glutPostRedisplay();
}

void reshape (int width, int height){
	glMatrixMode (GL_PROJECTION);	
	glLoadIdentity ();
	gluPerspective(45,(double)width/(double)height,0.1,1000);
	glViewport(0, 0,  width,  height);
	glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y){
	// YOU WRITE CODE IN THIS FUNCTION FOR ASSIGNMENT 2

	switch(key) {

	//Toggle animation	
	case 's':
		animation=!animation;
		break;

	// Use x, X, y, Y, z, and Z keys to move around in the world coordinate system
    
   // Multiply from right in view matrix means that we translate just before the view transformation
   // I.e. we are in the World Coordinate system
	case 'x':
		view_matrix=view_matrix*translate(translation_speed*Vector3(1,0,0));
		break;
	case 'X':
		view_matrix=view_matrix*translate(translation_speed*Vector3(-1,0,0));
		break;
	case 'y':
		view_matrix=view_matrix*translate(translation_speed*Vector3(0,1,0));
		break;
	case 'Y':
		view_matrix=view_matrix*translate(translation_speed*Vector3(0,-1,0));
		break;
	case 'z':
		view_matrix=view_matrix*translate(translation_speed*Vector3(0,0,1));
		break;
	case 'Z':
		view_matrix=view_matrix*translate(translation_speed*Vector3(0,0,-1));
		break;

	// Use i, I, o, O, p, and P keys to rotate observer around the view coordinate system axises



   // If we multiply from the left with the view matrix, we are just after the view transformation
   // I.e. we are in the View Coordinate system 
	case 'i':
		view_matrix=rotate_x(rotation_speed)*view_matrix;
		break;
	case 'I':
		view_matrix=rotate_x(-1*rotation_speed)*view_matrix;
		break;
	case 'o': 
		view_matrix=rotate_y(rotation_speed)*view_matrix;
		break;
	case 'O': 
		view_matrix=rotate_y(-1*rotation_speed)*view_matrix;
		break;
	case 'p': 
		view_matrix=rotate_z(rotation_speed)*view_matrix;
		break;
	case 'P': 
		view_matrix=rotate_z(-1*rotation_speed)*view_matrix;
		break;

	// Use a to move forward
    // Use A to move backward  
	case 'a':
		view_matrix=translate(translation_speed*Vector3(0,0,1))*view_matrix;
		break;
	case 'A':
		view_matrix=translate(-1*translation_speed*Vector3(0,0,1))*view_matrix;
		break;

		
	// Use j, J, k, K, l, and L keys to rotate objects around the objects axises
    
	// Each object has its own model matrix, this one is the first applied to the object
	// I.e. we are in the Object (model) Coordinate system
	case 'j': 
		object.model_matrix=object.model_matrix*rotate_x(rotation_speed);
		break;
	case 'J': 
		object.model_matrix=object.model_matrix*rotate_y(-rotation_speed);
		break;
	case 'k': 
		object.model_matrix=object.model_matrix*rotate_x(rotation_speed);
		break;
	case 'K': 
		object.model_matrix=object.model_matrix*rotate_x(-rotation_speed);
		break;
	case 'l': 
		object.model_matrix=object.model_matrix*rotate_z(rotation_speed);
		break;
	case 'L': 
		object.model_matrix=object.model_matrix*rotate_z(-rotation_speed);
		break;


	//... 

	// Scale objects with +/-
	// Also in the Object Coordinate sysetm   
	case '+':
		object.model_matrix=object.model_matrix*scale(Vector3(1.1,1.1,1.1));
		break;

	case '-': ;
		object.model_matrix=object.model_matrix*scale(Vector3(0.9,0.9,0.9));
		break;

	// Reset view matrix
	case 'r':
		view_matrix=look_at(Vector3(0, 10, 10), Vector3(0, 0, 0), Vector3(0, 1, 0));
		break;

    
	}
}

void init (){
	glEnable (GL_DEPTH_TEST);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	view_matrix=look_at(Vector3(0, 5, 5), Vector3(0, 0, 0), Vector3(0, 1, 0));

	//Setup lights
	light_list.clear();

	Color c1=Color(1.0,1.0,1.0);
	light_list.push_back(Light(Vector3(5.0f,-5.0f,0.0f), 0.4f*c1,0.7f*c1, 0.05f*c1));
	Color c2=Color(0.5f,0.4f,0.1f);
	light_list.push_back(Light(Vector3(-7.0f,0.0f,0.0f), 0.4f*c2,0.7f*c2, 0.05f*c2));
}

/////////////////////////////////////////////////////////////////////////////
//                               END OF FILE                               //
/////////////////////////////////////////////////////////////////////////////
